package com.fs.uc.api.inner.service;

import com.fs.uc.api.inner.dto.Park;
import com.fs.uc.api.inner.dto.RespModule;
import com.fs.uc.api.inner.dto.RespPerson;
import com.fs.uc.api.inner.dto.TestPermission;
import com.fs.uc.base.MinioUtil;
import com.fs.uc.base.repo.ModuleRepository;
import com.fs.uc.core.ModuleState;
import com.fs.uc.core.permcheck.SubjectInfo;
import com.fs.uc.base.domain.*;
import com.fs.uc.base.repo.OrgRepository;
import com.fs.uc.base.repo.PersonRepository;
import com.fs.uc.core.behavior.EnterpriseBehavior;
import com.fs.uc.core.behavior.PersonBehavior;
import com.fs.uc.core.permcheck.PermissionCheckerFactory;
import com.fs.uc.core.SubjectType;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author 崔超
 * 2021/12/9
 */
@ApplicationScoped
public class InnerService {
    @Inject
    PermissionCheckerFactory factory;
    @Inject
    OrgRepository orgRepo;
    @Inject
    PersonRepository personRepo;
    @Inject
    MinioUtil minio;
    @Inject
    PersonBehavior personBehavior;
    @Inject
    EnterpriseBehavior enterpriseBehavior;
    @Inject
    ModuleRepository moduleRepo;


    public Set<Role> getRolesOfPerson(Long personId) {
        return factory.getChecker(SubjectType.Person).getRoles(personId);
    }

    public Set<FunctionalModule> getAuthorizedModuleOfTenant(Long tenantId) {
        return factory.getChecker(SubjectType.Org).getAuthorizedModule(tenantId);
    }

    public List<RespModule> getAllModuleStateOfPark(Long parkId) {
        Set<FunctionalModule> authorizedModule = getAuthorizedModuleOfTenant(parkId);

        return moduleRepo.findAll().stream().map(module -> {
            boolean in = authorizedModule.contains(module);
            return in ? new RespModule(module.name, module.humanName, ModuleState.HasOpen)
                    : new RespModule(module.name, module.humanName, ModuleState.NotOpen);
        }).collect(Collectors.toList());
    }

    public boolean checkPermission(SubjectType subjectType, Long subjectId, String method, String path) {
        return factory.getChecker(subjectType).checkPermission(subjectId, method, path);
    }

    public Person createEnterpriseAndBoss(Long tenantId, Long enterpriseRemoteId, String phone, String enterpriseName, String personName) {
        Org enterprise = enterpriseBehavior.create(tenantId, enterpriseRemoteId, enterpriseName);
        Person boss = personBehavior.createByOrgAdmin(phone, personName);
        personBehavior.joinOrg(boss.id, enterprise.id);
        enterpriseBehavior.bindBoss(enterprise.id, boss.id);
        return boss;
    }

    public void transferEnterpriseBoss(Long enterpriseRemoteId, Long newBossId) {
        Org org = orgRepo.findByRemoteId(enterpriseRemoteId);
        enterpriseBehavior.bindBoss(org.id, newBossId);
    }

    public List<RespPerson> getPersons(List<Long> IdList) throws Exception {
        List<Person> persons = personRepo.findByIds(IdList);
        List<RespPerson> list = new ArrayList<>();
        for (Person p : persons) {
            String photoUrl = minio.preview(p.id + ".jpg");
            list.add(new RespPerson(p.id, p.name, p.phone, photoUrl, p.openid));
        }
        return list;

    }


    public SubjectInfo getSubjectInfo(SubjectType type, Long subjectId) {
        return factory.getChecker(type).getSubjectInfo(subjectId);
    }

    public Person getPerson(Long personId) {
        return personRepo.getById(personId);
    }

    public List<Park> getAllPark() {
        List<Org> enterpriseList = orgRepo.findByType(OrgType.Enterprise).stream()
                .filter(org -> org.parent != null).collect(Collectors.toList());

        Map<Org, List<Org>> map = new HashMap<>();
        enterpriseList.forEach(org -> {
            if (map.containsKey(org.parent)) {
                map.get(org.parent).add(org);
            } else {
                List<Org> enterprises = new ArrayList<>();
                enterprises.add(org);
                map.put(org.parent, enterprises);
            }
        });

        List<Park> list = new ArrayList<>();
        for (Org parent : map.keySet()) {
            List<Long> enterpriseIds = map.get(parent).stream()
                    .map(org -> org.remoteId).collect(Collectors.toList());
            list.add(new Park(parent.id, parent.name, enterpriseIds));
        }

        return list;
    }

    //单元测试使用
    public List<TestPermission> testUserPermission(Long personId) {
        return factory.getChecker(SubjectType.Person).getPermissions(personId)
                .stream()
                .sorted((p1, p2) -> (int) (p1.id - p2.id))
                .map(p -> new TestPermission(p.id, p.resource))
                .collect(Collectors.toList());
    }

    public SubjectInfo testUserSubjectInfo(Long personId) {
        return factory.getChecker(SubjectType.Person).getSubjectInfo(personId);
    }

}
